package main;

import java.awt.Button;
import java.awt.Choice;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.ArrayList;

public class FightUI extends PhaseUI {

	public FightMouse myMouse;
	
	public Button fightBattle;
	public Button rollDice;
	public Button doneRetreating;
	public Button barrierDoneFallingBack;
	public Button strikeButton;
	public Button barrierStrikeButton;
	public Button chargeBarrier;
	
	public Choice goodChoice;
	public Choice badChoice;
	public Choice barrierAttackerChoice;
	
	public Choice attackers;
	public Choice targets;
	
	public void beginPhase() {
		myMouse = new FightMouse();
		myMouse.myUI = myUI;
		myMouse.myFightUI = this;
		myUI.addMouseListener(myMouse);
		myUI.addMouseMotionListener(myMouse);
		
		// Disable end phase while there are active fights out there
		myUI.endPhase.setEnabled(false);
		
		
		// Set up the fight components
		setupButtons();
		
		// Check to see if battles is empty
		if(myUI.game.battles.isEmpty()){
			myUI.endPhase.setEnabled(true);
		}

		myUI.revalidate();
		myUI.repaint();
	}
	
	public void checkBattles() {
		if(myUI.game.battles.isEmpty()){
			myUI.endPhase.setEnabled(true);
		}
	}
	
	public void setupButtons() {
		fightBattle = new Button("Fight Battle");
		fightBattle.setBounds(myUI.dim.width-100,50,100,50);
		fightBattle.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				if (myUI.selectedBattle != null && myUI.game.battles.contains(myUI.selectedBattle)) {
					goodChoice = new Choice();
					badChoice = new Choice();
					
					// Populate the unit choices
					for(Unit u : myUI.selectedBattle.goodUnits) {
						goodChoice.add(u.toChoiceString());
					}
					for(Unit u : myUI.selectedBattle.badUnits) {
						badChoice.add(u.toChoiceString());
					}
					goodChoice.setLocation(myUI.dim.width - 200, myUI.dim.height/2 - 30);
					badChoice.setLocation(myUI.dim.width - 200, myUI.dim.height/2 + 30);
					Unit goodUnit = myUI.selectedBattle.goodUnits.get(0);
					int count = 0;
					for (Equipment equip : goodUnit.equipmentList) {
						if (equip.options != null) {
							equip.options.setLocation(myUI.dim.width - 200, myUI.dim.height/2 - 60 - 30*count);
							myUI.add(equip.options);
							count += 1;
						}
					}
					Unit badUnit = myUI.selectedBattle.badUnits.get(0);
					count = 0;
					for (Equipment equip : badUnit.equipmentList) {
						if (equip.options != null) {
							equip.options.setLocation(myUI.dim.width - 200, myUI.dim.height/2 + 60 + 30*count);
							myUI.add(equip.options);
							count += 1;
						}
					}
					ItemListener i = new ItemListener() {
						public void itemStateChanged(ItemEvent e) {
							myUI.removeByName("Equipment Options");
							Unit goodUnit = myUI.selectedBattle.goodUnits.get(goodChoice.getSelectedIndex());
							int count = 0;
							for (Equipment equip : goodUnit.equipmentList) {
								if (equip.options != null) {
									equip.options.setLocation(myUI.dim.width - 200, myUI.dim.height/2 - 60 - 30*count);
									myUI.add(equip.options);
									count += 1;
								}
							}
							Unit badUnit = myUI.selectedBattle.badUnits.get(badChoice.getSelectedIndex());
							count = 0;
							for (Equipment equip : badUnit.equipmentList) {
								if (equip.options != null) {
									equip.options.setLocation(myUI.dim.width - 200, myUI.dim.height/2 + 60 + 30*count);
									myUI.add(equip.options);
									count += 1;
								}
							}
						}
					};
					goodChoice.addItemListener(i);
					badChoice.addItemListener(i);

					myUI.add(goodChoice);
					myUI.add(badChoice);
					
					fightBattle.setEnabled(false);
					rollDice.setVisible(true);
					
					myUI.revalidate();
					myUI.repaint();
				}
			}
		});
		myUI.add(fightBattle);
		if (myUI.game.battles.size() == 0)
			fightBattle.setEnabled(false);
		
		
		
		rollDice = new Button("Roll Dice");
		rollDice.setBounds(myUI.dim.width-100,100,100,50);
		rollDice.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				// Apply the chosen options
				for (Unit u : myUI.selectedBattle.goodUnits) {
					u.battleDice = u.attacks;
					u.battleBonus = 0;
					u.woundDice = u.attacks;
					u.woundBonus = 0;
					for (Equipment equip : u.equipmentList) {
						equip.applyOptions();
					}
				}
				for (Unit u : myUI.selectedBattle.badUnits) {
					u.battleDice = u.attacks;
					u.battleBonus = 0;
					u.woundDice = u.attacks;
					u.woundBonus = 0;
					for (Equipment equip : u.equipmentList) {
						equip.applyOptions();
					}
				}
				// Clean up choices
				myUI.remove(goodChoice);
				myUI.remove(badChoice);
				myUI.removeByName("Equipment Options");
				rollDice.setVisible(false);
				
				// Where we go next is dependent on what kind of battle we're dealing with
				if (!(myUI.selectedBattle instanceof BarrierBattle)){
					// Move to next stage
					myUI.storeVisibleComponents();
					myUI.disableComponents();
					myUI.selectedBattle.rollFightDice(doneRetreating);
				}
				else if (myUI.selectedBattle instanceof BarrierBattle) {
					// How we handle the barrier fight depends on:
					//    - Which side is outnumbered (if one defender, do multiple fights)
					//    - Whether the attack is coming from both sides (No obstacle bonus when striking)
					if (((BarrierBattle)myUI.selectedBattle).getAttackers().size() == 1) {
						// Only need to do one normal fight
						attackers = new Choice();
						targets = new Choice();
						attackers.setLocation(myUI.dim.width - 200, myUI.dim.height/2 - 30);
						targets.setLocation(myUI.dim.width - 200, myUI.dim.height/2 + 30);
						myUI.storeVisibleComponents();
						myUI.disableComponents();
						((BarrierBattle)myUI.selectedBattle).rollBarrierFightDice(doneRetreating, barrierStrikeButton, 
																	attackers, targets);  // Only adds retreat move if defender won
					}
					else if (((BarrierBattle)myUI.selectedBattle).getAttackers().size() > 1) {
						// Need to set up multiple fights somehow, bring back whichever the appropriate choice is to choose who attacks first
						// Then do fights one at a time until either the defender list is empty - advance over barrier
						// or all have fought (then need to retreat all)
						if (!((BarrierBattle)myUI.selectedBattle).attackFromBothSides) {
							barrierAttackerChoice = new Choice();
							barrierAttackerChoice.setLocation(myUI.dim.width - 200, myUI.dim.height/2 - 30);
							for (Unit u : ((BarrierBattle)myUI.selectedBattle).getAttackers()) {
								barrierAttackerChoice.add(u.toChoiceString());
							}
							myUI.add(barrierAttackerChoice);
							
							chargeBarrier.setVisible(true);
						}
						else {
							// Being attacked from both sides, treat it like a normal fight
							myUI.storeVisibleComponents();
							myUI.disableComponents();
							myUI.selectedBattle.rollFightDice(doneRetreating);
						}
					}
				}
				
				myUI.revalidate();
				myUI.repaint();
			}
		});
		myUI.add(rollDice);
		rollDice.setVisible(false);
		
		
		
		
		
		chargeBarrier = new Button("Charge Barrier");
		chargeBarrier.setBounds(myUI.dim.width-100, 100, 100, 50);
		chargeBarrier.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				chargeBarrier.setVisible(false);
				// Get the selected unit from barrierAttackerChoice
				Unit charger = Utils.getFromListByString(((BarrierBattle)myUI.selectedBattle).getAttackers(), 
														  barrierAttackerChoice.getSelectedItem());
				
				attackers = new Choice();
				targets = new Choice();
				attackers.setLocation(myUI.dim.width - 200, myUI.dim.height/2 - 30);
				targets.setLocation(myUI.dim.width - 200, myUI.dim.height/2 + 30);
				// do a fight between defender and attacker
				myUI.storeVisibleComponents();
				myUI.disableComponents();
				((BarrierBattle)myUI.selectedBattle).rollDiceOneAttacker(charger, doneRetreating, barrierStrikeButton, attackers, targets);
				
				// do visibility/enable UI stuff (also happens throughout for various branching results)
				myUI.remove(barrierAttackerChoice);
				chargeBarrier.setVisible(false);
				myUI.revalidate();
				myUI.repaint();
			}
		});
		myUI.add(chargeBarrier);
		chargeBarrier.setVisible(false);
		
		
		
		
		doneRetreating = new Button("Done Retreating");
		doneRetreating.setBounds(myUI.dim.width-100, 100, 100, 50);
		doneRetreating.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				for (Unit u : myUI.selectedBattle.losers) {
					if (u.moveLeft > 0.2 || u.layingDown || u.isTransfixed) {
						u.hasRetreated = false;
						UI.messageLog.add(u.toChoiceString() + " doesn't retreat");
					}
				}
				
				doneRetreating.setVisible(false);
				
				// Add strike paraphernalia
				attackers = new Choice();
				targets = new Choice();
				attackers.setLocation(myUI.dim.width - 200, myUI.dim.height/2 - 30);
				targets.setLocation(myUI.dim.width - 200, myUI.dim.height/2 + 30);
				for (Unit u : myUI.selectedBattle.winners) {
					if (u.layingDown) {
						// Stand up
						u.layingDown = false;
					}
					else {
						for (int i = 0; i < u.getWoundDice(); i++) {
							attackers.add(u.toChoiceString());
						}
					}
				}
				for (Unit u : myUI.selectedBattle.losers) {
					if (u.hasRetreated)
						targets.add(u.toChoiceString());
					else
						targets.add(u.toChoiceString() + "-(T)");
				}
				
				// If the winning side was laying down, they may need to stand up instead of striking
				if (attackers.getItemCount() == 0 || targets.getItemCount() == 0) {
					myUI.selectedBattle.cleanUp();
					
					if(myUI.game.battles.isEmpty()){
						myUI.endPhase.setEnabled(true);
					}
					else {
						fightBattle.setEnabled(true);
					}
					return;
				}
				
				// Otherwise, do stuff
				myUI.add(attackers);
				myUI.add(targets);
				
				if (myUI.selectedBattle instanceof BarrierBattle && !((BarrierBattle)myUI.selectedBattle).attackFromBothSides)
					barrierStrikeButton.setVisible(true);
				else {
					strikeButton.setVisible(true);
				}
				
				myUI.revalidate();
				myUI.repaint();
			}
		});
		myUI.add(doneRetreating);
		doneRetreating.setVisible(false);
		
		
		
		
		barrierDoneFallingBack = new Button("Done Falling Back");
		barrierDoneFallingBack.setBounds(myUI.dim.width-100, 100, 100, 50);
		barrierDoneFallingBack.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				for (Unit u : ((BarrierBattle)myUI.selectedBattle).getAttackers()) {
					if (u.moveLeft == 1) {
						UI.messageLog.add("Someone hasn't fallen back");
						return;
					}
				}
				
				barrierDoneFallingBack.setVisible(false);
				
				ArrayList<Unit> unfought = new ArrayList<Unit>();
				for (Unit u : ((BarrierBattle)myUI.selectedBattle).getAttackers()) {
					if (u.hasFought == false) {
						unfought.add(u);
					}
				}
				if (unfought.size() == 0) {
					myUI.selectedBattle.cleanUp();
					
					if(myUI.game.battles.isEmpty()){
						myUI.endPhase.setEnabled(true);
					}
					else {
						fightBattle.setEnabled(true);
					}
				}
				else {
					// need to re-enable chargeBarrier and refresh+reenable the charge barrier choice
					barrierAttackerChoice = new Choice();
					barrierAttackerChoice.setLocation(myUI.dim.width - 200, myUI.dim.height/2 - 30);
					for (Unit u : unfought) {
						barrierAttackerChoice.add(u.toChoiceString());
					}
					myUI.add(barrierAttackerChoice);
					
					chargeBarrier.setVisible(true);
				}
				myUI.revalidate();
				myUI.repaint();
			}
		});
		myUI.add(barrierDoneFallingBack);
		barrierDoneFallingBack.setVisible(false);
		
		
		
		
		
		strikeButton = new Button("Strike");
		strikeButton.setBounds(myUI.dim.width-100, 100, 100, 50);
		strikeButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				Unit attacker = myUI.selectedBattle.getSelectedUnit(attackers);
				Unit target = myUI.selectedBattle.getSelectedUnit(targets);
				
				
				// Strike
				Button doneStriking = new Button();
				doneStriking.addMouseListener(new MouseListener() {
					public void mouseClicked(MouseEvent e) {						
						// Remove attacker
						attackers.remove(attackers.getSelectedIndex());
						
						// Remove target if dead
						if(target.getWounds() <= 0) {
							targets.remove(targets.getSelectedIndex());
						}
						
						
						// Check for end conditions
						if (attackers.getItemCount() == 0 || targets.getItemCount() == 0) {
							myUI.selectedBattle.cleanUp();
							strikeButton.setVisible(false);
							myUI.remove(attackers);
							myUI.remove(targets);
							
							if(myUI.game.battles.isEmpty()){
								myUI.endPhase.setEnabled(true);
							}
							else {
								fightBattle.setEnabled(true);
							}
						}
						myUI.remove(doneStriking);
						myUI.refreshSelectChoice();
						myUI.revalidate();
						myUI.repaint();
					}
					public void mouseEntered(MouseEvent arg0) {}
					public void mouseExited(MouseEvent e) {}
					public void mousePressed(MouseEvent e) {}
					public void mouseReleased(MouseEvent e) {}
				});
				attacker.strike(target, target.hasRetreated, doneStriking);

				myUI.refreshSelectChoice();
				myUI.revalidate();
				myUI.repaint();
			}
		});
		myUI.add(strikeButton);
		strikeButton.setVisible(false);
		
		
		barrierStrikeButton = new Button("Strike!");
		barrierStrikeButton.setBounds(myUI.dim.width-100, 100, 100, 50);
		barrierStrikeButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				Unit attacker = myUI.selectedBattle.getSelectedUnit(attackers);
				Unit target = myUI.selectedBattle.getSelectedUnit(targets);
				
				attackers.setEnabled(false);
				targets.setEnabled(false);
				
				Button doneStriking = new Button();
				doneStriking.addMouseListener(new MouseListener() {
					public void mouseClicked(MouseEvent e){
						attackers.setEnabled(true);
						targets.setEnabled(true);
						
						// Remove attacker
						attackers.remove(attackers.getSelectedIndex());
						
						// Remove target if dead
						if(target.getWounds() <= 0) {
							targets.remove(targets.getSelectedIndex());
							((BarrierBattle)myUI.selectedBattle).perishedUnits.add(target);
							if (attacker.armyIndex != ((BarrierBattle)myUI.selectedBattle).defenderIndex) {
								UI.messageLog.add("Killed enemy " + target.toChoiceString() + ", taking the barricade!");
								// If only one attacker, take space of killed unit
								if (myUI.selectedBattle.getUnitsByIndex(attacker.armyIndex).size() == 1) {
									attacker.x = target.x;
									attacker.y = target.y;
								}
								// Otherwise we have multiple attackers against a single unit, any who haven't fought can cross
								else {
									int numJumped = 0;
									((BarrierBattle)myUI.selectedBattle).barrier.takeBarrier(attacker);
									for (Unit u : myUI.selectedBattle.getUnitsByIndex(attacker.armyIndex)) {
										if (u.hasFought == false) {
											int oldX = u.x;
											int oldY = u.y;
											((BarrierBattle)myUI.selectedBattle).barrier.takeBarrier(u);
											if (u.x != oldX || u.y != oldY) 
												numJumped += 1;
										}
									}
									if (numJumped == 0){
										attacker.x = target.x;
										attacker.y = target.y;
									}
								}
							}
						}
						
						boolean normalCleanup = false;
						ArrayList<Unit> unfought = new ArrayList<Unit>();
						for (Unit u : ((BarrierBattle)myUI.selectedBattle).getAttackers()) {
							if (u.hasFought == false) {
								unfought.add(u);
							}
						}
						// Check for end conditions
						if (attackers.getItemCount() == 0) {
							if (target.getWounds() > 0 && target.armyIndex == ((BarrierBattle)myUI.selectedBattle).defenderIndex) {
								// If target is still alive and striker is an attacker, need to fall back
								attacker.uncontactTerrain();
								attacker.uncontactUnits();
								attacker.moveLeft = 1;
								for (Unit ally : attacker.army.units) {
									if (Utils.inchDist(attacker, ally) < 2 && ally.battle == null) {
										ally.moveLeft = 1;
									}
								}
								barrierStrikeButton.setVisible(false);
								myUI.remove(attackers);
								myUI.remove(targets);
								barrierDoneFallingBack.setVisible(true);
							}
							else if (target.getWounds() <= 0 && target.armyIndex == ((BarrierBattle)myUI.selectedBattle).defenderIndex) {
								// Killed the target, do normal cleanup (already advanced over barricade)
								normalCleanup = true;
							}
							else {
								// Defender won, check whether or not battle is finished
								if (unfought.size() == 0)
									normalCleanup = true;
								else {
									barrierAttackerChoice = new Choice();
									barrierAttackerChoice.setLocation(myUI.dim.width - 200, myUI.dim.height/2 - 30);
									for (Unit u : unfought) {
										barrierAttackerChoice.add(u.toChoiceString());
									}
									myUI.add(barrierAttackerChoice);
									myUI.remove(attackers);
									myUI.remove(targets);
									
									chargeBarrier.setVisible(true);
								}
							}
						}
						else if (targets.getItemCount() == 0) {
							// target is dead, if it was defender to normal cleanup, otherwise reset chargeBarrier
							if (target.armyIndex == ((BarrierBattle)myUI.selectedBattle).defenderIndex)
								normalCleanup = true;
							else {
								if (unfought.size() == 0)
									normalCleanup = true;
								else {
									barrierAttackerChoice = new Choice();
									barrierAttackerChoice.setLocation(myUI.dim.width - 200, myUI.dim.height/2 - 30);
									for (Unit u : unfought) {
										barrierAttackerChoice.add(u.toChoiceString());
									}
									myUI.add(barrierAttackerChoice);
									myUI.remove(attackers);
									myUI.remove(targets);
									
									chargeBarrier.setVisible(true);
								}
							}
						}
						if (normalCleanup) {
							myUI.selectedBattle.cleanUp();
							barrierStrikeButton.setVisible(false);
							myUI.remove(attackers);
							myUI.remove(targets);
							
							if(myUI.game.battles.isEmpty()){
								myUI.endPhase.setEnabled(true);
							}
							else {
								fightBattle.setEnabled(true);
							}
						}
						myUI.refreshSelectChoice();
						myUI.revalidate();
						myUI.repaint();
					}
					public void mouseEntered(MouseEvent e) {}
					public void mouseExited(MouseEvent e) {}
					public void mousePressed(MouseEvent e) {}
					public void mouseReleased(MouseEvent e) {}
				});
				
				
				if (attacker.armyIndex != ((BarrierBattle)myUI.selectedBattle).defenderIndex){
					// Roll for barrier
					DieRoll barrierRoll = new DieRoll(attacker, myUI.dim.width-200, myUI.dim.height/2-130, 
										 			   "4+ to pass barrier", myUI);
					
					if (!barrierRoll.isModifiable()){
						int barrierNum = barrierRoll.getRoll();
						UI.messageLog.add("Rolling to strike past barrier: " + barrierRoll);
						if (barrierNum > 3) {
							// Strike
							attacker.strike(target, doneStriking);
						}
					}
					else {
						myUI.storeVisibleComponents();
						myUI.disableComponents();
						ActionListener mightDone = new ActionListener() {
							public void actionPerformed(ActionEvent e) {
								int barrierNum = barrierRoll.getRoll();
								UI.messageLog.add("Rolling to strike past barrier: " + barrierRoll);
								myUI.reenableComponents();
								myUI.disableMight();
								if (barrierNum > 3) {
									// Strike
									attacker.strike(target, doneStriking);
								}
							}
						};
						myUI.enableMight(mightDone);
					}
				}
				else {
					attacker.strike(target, target.hasRetreated, doneStriking);
				}
				
				myUI.refreshSelectChoice();
				myUI.revalidate();
				myUI.repaint();
			}
		});
		myUI.add(barrierStrikeButton);
		barrierStrikeButton.setVisible(false);
	}
	
	public void endPhase() {
		// Clean up shoot stuff
		myUI.removeMouseListener(myMouse);
		myUI.removeMouseMotionListener(myMouse);
		myUI.remove(fightBattle);
		myUI.remove(rollDice);
		myUI.remove(doneRetreating);
		myUI.remove(strikeButton);
		

		myUI.game.endPhase();
			
		// Create a HeroicMoveUI and set it to be the new phase
		HeroicMoveUI moveUI = new HeroicMoveUI();
		moveUI.myUI = myUI;
		myUI.phaseUI = moveUI;
		myUI.phaseUI.beginPhase();
	}
	
	public void paint(Graphics bufferG) {
    	if (rollDice.isVisible()){
    		bufferG.drawString("fighting", myUI.dim.width-200, myUI.dim.height/2+12);
    	}
    	else if (strikeButton.isVisible() || barrierStrikeButton.isVisible()){
    		bufferG.drawString("strikes", myUI.dim.width-200, myUI.dim.height/2+12);
    	}
    	else if (chargeBarrier.isVisible()) {
    		bufferG.drawString("to charge the barrier next", myUI.dim.width-200, myUI.dim.height/2+12);
    	}
	}
}
